/*
 * @Description: 
 * @Author: duan_shuangjun 丶
 * @Date: 2025-08-20 14:41:05
 * @LastEditTime: 2025-10-11 19:49:53
 */
import { app, BrowserWindow } from 'electron'
import { fileURLToPath } from 'node:url'
import path from 'node:path'
import { execSync } from 'node:child_process'

process.env.LANG = 'zh_CN.UTF-8'
process.env.LC_ALL = 'zh_CN.UTF-8'
try { require('node:child_process').execSync('chcp 65001'); } catch { }
// 为 ES 模块环境添加 Node.js 全局变量定义
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

// 确保这些全局变量在 better-sqlite3 中可用
globalThis.__filename = __filename
globalThis.__dirname = __dirname

import { initDatabase, closeDatabase } from './database'
import { registerDatabaseHandlers } from './ipc/database'
import { registerSystemHandlers } from './ipc/system'
import { registerCXTDatabaseHandlers } from './cxtmssql/ipc'
import { initCXTDatabase, closeCXTDatabase } from './cxtmssql/database'
import { registerWebSocketLogHandlers, writeLog } from './ipc/wsLogger'

// The built directory structure
//
// ├─┬─┬ dist
// │ │ └── index.html
// │ │
// │ ├─┬ dist-electron
// │ │ ├── main.js
// │ │ └── preload.mjs
// │
process.env.APP_ROOT = path.join(__dirname, '..')

// 🚧 Use ['ENV_NAME'] avoid vite:define plugin - Vite@2.x
export const VITE_DEV_SERVER_URL = process.env['VITE_DEV_SERVER_URL']
export const MAIN_DIST = path.join(process.env.APP_ROOT, 'dist-electron')
export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist')

process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL ? path.join(process.env.APP_ROOT, 'public') : RENDERER_DIST

let win: BrowserWindow | null

function logGlobalError(level: 'ERROR' | 'FATAL', message: string, error: any) {
  const timestamp = new Date().toISOString()
  const errorPayload = error instanceof Error
    ? { message: error.message, stack: error.stack }
    : { message: typeof error === 'string' ? error : JSON.stringify(error) }
  const logLine = `${timestamp} | ${level} | GLOBAL | ${message} | DATA:${JSON.stringify(errorPayload)}`
  writeLog(logLine).catch(err => {
    console.error('写入全局异常日志失败:', err)
  })
}

function setupGlobalExceptionHandlers() {
  process.on('uncaughtException', (error) => {
    console.error('捕获到未处理异常:', error)
    logGlobalError('FATAL', 'uncaughtException', error)
  })

  process.on('unhandledRejection', (reason) => {
    console.error('捕获到未处理的Promise拒绝:', reason)
    logGlobalError('ERROR', 'unhandledRejection', reason)
  })

  process.on('exit', (code) => {
    const info = { code }
    const logLine = `${new Date().toISOString()} | INFO | GLOBAL | process.exit | DATA:${JSON.stringify(info)}`
    writeLog(logLine).catch(err => {
      console.error('写入退出日志失败:', err)
    })
  })
}

setupGlobalExceptionHandlers()

function resolveAppIcon() {
  // Use .ico for Windows title bar; works in dev and production
  return app.isPackaged
    ? path.join(process.resourcesPath, 'build', 'icon.ico')
    : path.join(process.env.APP_ROOT, 'build', 'icon.ico')
}

function createWindow() {
  // 创建一个加载窗口
  const splash = new BrowserWindow({
    width: 500,
    height: 300,
    transparent: true,
    frame: false,
    alwaysOnTop: true,
    icon: resolveAppIcon()
  })

  // 加载启动页面
  splash.loadFile(path.join(process.env.VITE_PUBLIC, 'splash.html'))

  // 创建主窗口但先不显示
  win = new BrowserWindow({
    minHeight: 900,
    minWidth: 1600,
    useContentSize: true,
    // 是否默认开启全屏模式
    fullscreen: false,
    icon: resolveAppIcon(),
    webPreferences: {
      preload: path.join(__dirname, 'preload.mjs'),
    },
    autoHideMenuBar: true,
    show: false
  })

  // 主窗口准备好显示时
  win.once('ready-to-show', () => {
    splash.destroy()
    if (win) {
      win.maximize()
      win.show()
    }
  })

  win.webContents.on('render-process-gone', (event, details) => {
    const logLine = `${new Date().toISOString()} | FATAL | RENDERER | render-process-gone | DATA:${JSON.stringify(details)}`
    writeLog(logLine).catch(err => {
      console.error('写入渲染进程异常日志失败:', err)
    })
  })

  // 彻底移除菜单栏（防止按 Alt 显示）
  win.removeMenu()

  // 打开调试工具，便于排查白屏（打包发版时 ---生产或测试不需要调试请务必关闭）
  win.webContents.openDevTools({ mode: 'detach' })

  // Test active push message to Renderer-process.
  win.webContents.on('did-finish-load', () => {
    win?.webContents.send('main-process-message', (new Date).toLocaleString())
  })

  if (VITE_DEV_SERVER_URL) {
    win.loadURL(VITE_DEV_SERVER_URL)
  } else {
    // win.loadFile('dist/index.html')
    win.loadFile(path.join(RENDERER_DIST, 'index.html'))
  }
}

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
    win = null
  }
})

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow()
  }
})

app.whenReady().then(async () => {
  try {
    // 初始化本地数据库
    await initDatabase()
    console.log('本地数据库初始化完成')

    // 初始化 CXT SQL Server 数据库
    try {
      await initCXTDatabase()
      console.log('CXT SQL Server 数据库初始化完成')
    } catch (error) {
      console.warn('CXT SQL Server 数据库初始化失败，将跳过 CXT 功能:', error.message)
    }

    // 注册IPC处理器
    registerDatabaseHandlers()
    // 注册系统IPC处理器
    registerSystemHandlers()
    // 注册 CXT 数据库处理器
    registerCXTDatabaseHandlers()
    
    // 注册WebSocket日志处理器
    registerWebSocketLogHandlers()
    
    console.log('IPC处理器注册完成')

    // 等待一小段时间确保数据库完全初始化
    await new Promise(resolve => setTimeout(resolve, 500))

    // 创建窗口
    createWindow()
  } catch (error) {
    console.error('应用启动失败:', error)
    app.quit()
  }
})

// 应用退出时关闭数据库连接
app.on('before-quit', async () => {
  await closeDatabase()
  await closeCXTDatabase()
})